package org.pz.handler;

import lombok.extern.slf4j.Slf4j;
import org.pz.cllient.UserClient;
import org.pz.config.MallProperties;
import org.pz.constant.MallSecurityConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * 设权：决定访问某个资源需要有哪些角色
 * */
@Slf4j
@Configuration
public class MallSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    @Autowired
    private UserClient userClient;

    @Autowired
    private MallProperties mallProperties;

    /*
     * 根据传入的请求对象，获取该请求所需的访问控制元数据，返回一个 ConfigAttribute 对象的集合
     */
    @Override
    public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {

        log.info("授权服务");

        FilterInvocation fi = (FilterInvocation)o;
        HttpServletRequest httpRequest = fi.getHttpRequest();

        //请求路径
        String requestURI = httpRequest.getRequestURI();

        log.info("路径：{}", requestURI);

        //1. 判断是否白名单的内容
        for(String whiteUrl : mallProperties.getWhiteUrls()) {
            if(new AntPathRequestMatcher(whiteUrl).matches(httpRequest)) {
                return MallSecurityConstants.PERMISSION_ALL;
            }
        }

        //2. 根据请求获取哪些角色可以访问该资源
        List<String> rolesByAsset = userClient.findRolesByAsset(requestURI);

        //3. 如果没有获取到对应角色，应该就是谁都能访问
        if(rolesByAsset == null || rolesByAsset.isEmpty()){
            return MallSecurityConstants.PERMISSION_ALL;
        }

        //4. 获取到对应角色封装后返回
        Set<ConfigAttribute> attributes = new HashSet<>();
        rolesByAsset.forEach(s -> attributes.add(new SecurityConfig(s.trim())));

        return attributes;
    }

    /*
    * 获取系统中已定义的访问控制y元数据，返回一个 ConfigAttribute 对象的集合，目前用不着
    */
    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return Collections.emptyList();
    }

    /*
     * 判断该类是否支持传入的参数类型，如果支持则返回 true，否则返回 false，目前也不知道啥意思
     */
    @Override
    public boolean supports(Class<?> aClass) {
        return FilterInvocation.class.isAssignableFrom(aClass);
    }
}
